package com.wzh.project.redis.context;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import com.wzh.project.common.Constants;
import com.wzh.project.redis.config.RedisConfig;
import com.wzh.project.utils.ConfigLoader;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisContext {
	private Map<String,Object> jedisCache=new HashMap<String,Object>();
	private Map<String,RedisConfig> configCache=new HashMap<String,RedisConfig>();
	
	private static RedisContext jc = new RedisContext();
	private RedisContext() {
		
	}
	public static RedisContext getInstance() {
		return jc;
	}
	
	public Map<String, RedisConfig> getConfigCache() {
		return configCache;
	}
	
	public Object getJedis(String name) throws Exception {
		 if(jedisCache.get(name)==null) {
			//锁定，初始化
			 synchronized (name.intern()) {
				 if(jedisCache.get(name)==null) {
					 init(name);
				 }
			}
		 }
		 Object jedisPool = jedisCache.get(name);
		 return jedisPool;	 
	 }
	 
	 public void loadConfig(String name) throws Exception {
		 if(configCache.isEmpty()) {
			 synchronized (configCache) {
				loadConfigFromStorage(name);
			}
		 }
	 }
	
	 private void loadConfigFromStorage(String name) throws Exception {
		RedisConfig jc = new RedisConfig();
 		Map<String, Object> properties = ConfigLoader.getInstance().loadFile(Constants.REDIS_CONFIG).get(0);
 		String hostset = (String)properties.get("hosts");
 		String[] hosts = hostset.split(",");
 		for (String host :hosts) {
 			String[] hostandport = host.split(":");
 			if(hostandport.length!=2) {
 				throw new Exception("hosts配置错误！");
 			}
 			jc.getHostAndPortList().add(new String[] {hostandport[0], hostandport[1]});
 		}
 		String requestQueue = (String)properties.get("request_queue");
 		if(requestQueue==null) {
 			jc.setRequestQueue(name);
 		}else {
 			jc.setRequestQueue(requestQueue);
 		}
 		String mode = (String)properties.get("mode");
 		jc.setSingleMode("single".equals(mode));
 		String maxIdleCons = (String)properties.get("max_idle_cons");
 		if(maxIdleCons!=null) {
 			jc.setMaxIdleCons(Integer.parseInt(maxIdleCons));
 		}
 		String maxTolalCons = (String)properties.get("max_cons");
 		if (maxTolalCons!=null) {
			jc.setMaxTolalCons(Integer.parseInt(maxTolalCons));
		}
		String minIdleCons = (String)properties.get("min_idle_cons");
 		if (minIdleCons!=null) {
			jc.setMinIdleCons(Integer.parseInt(minIdleCons));
		}
		String maxWaitTime = (String)properties.get("max_wait_time_con");
 		if (maxWaitTime!=null) {
			jc.setMaxWaitTime(Integer.parseInt(maxWaitTime));
		}
		String tob = (String)properties.get("test_on_borrow");
 		if (tob!=null) {
			jc.setTestOnBorrow("Y".equalsIgnoreCase(tob));
		}
		String count = (String)properties.get("consumer_count");
 		if (count!=null) {
			jc.setConsumerThreadCount(Integer.parseInt(count));
		}
		String consumerMaxThread = (String)properties.get("consumer_max_Thread_count");
 		if (consumerMaxThread!=null) {
			jc.setConsumerMaxThread(Integer.parseInt(consumerMaxThread));
		}
		String role = (String)properties.get("role");
 		jc.setRole(role);
 		
 		
 		String  connectionTimeout=(String)properties.get("consumer_count");
 		jc.setConnectionTimeout(connectionTimeout==null?100000:Integer.parseInt(connectionTimeout));
 		String  soTimeout=(String)properties.get("soTimeout");
 		jc.setSoTimeout(soTimeout==null?120000:Integer.parseInt(soTimeout));
 		String  maxAttempts=(String)properties.get("maxAttempts");
 		jc.setMaxAttempts(maxAttempts==null?3:Integer.parseInt(maxAttempts));
 		String password=(String)properties.get("password");
 		if (password!=null) {
			jc.setPassword(password);
		}
		configCache.put(name, jc);
	}

	public void  init(String name) throws Exception {
		 	loadConfig(name);
		 	RedisConfig config = configCache.get(name);
		 	if(config == null) {
		 		throw new Exception("配置中没有名字为"+name+"的jedis配置，请配置！");
		 	}
		 	
		 	//分为单点模式还是集群模式
		 	List<String[]> cluster=config.getHostAndPortList();
		 	if(config.getSingleMode()) {
		 		String[] ipport = cluster.get(0);
		 		Object jedisPool = null;
		 		 if(config.getPassword()==null) {
		 			jedisPool = new JedisPool(new JedisPoolConfig(), ipport[0], Integer.parseInt(ipport[1]), config.getSoTimeout());
		 		 }else {
		 			jedisPool = new JedisPool(new JedisPoolConfig(), ipport[0], Integer.parseInt(ipport[1]), config.getSoTimeout(),config.getPassword());
		 		 }
	    		jedisCache.put(name, jedisPool);
	    		return;
		 	}
	    	Set<HostAndPort> hostAndPortsSet = new HashSet<HostAndPort>();
	    	for(String[] ipport : cluster) {
	    		hostAndPortsSet.add(new HostAndPort(ipport[0], Integer.parseInt(ipport[1])));
	    	}
	    	//加载配置文件
	    	JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
	    	initJedisConfig(config,jedisPoolConfig);
	    	JedisCluster jedis = null;
	        if(config.getPassword()==null) {
	        	jedis = new JedisCluster(hostAndPortsSet, config.getConnectionTimeout(), config.getSoTimeout(), config.getMaxAttempts(),  jedisPoolConfig);
	        }else {
	        	jedis = new JedisCluster(hostAndPortsSet, config.getConnectionTimeout(), config.getSoTimeout(),config.getMaxAttempts(),config.getPassword(), jedisPoolConfig);
	        }
	        jedisCache.put(name, jedis);
	    }

	private void initJedisConfig(RedisConfig config,JedisPoolConfig jedisPoolConfig) {
		 // Jedis连接池配置
        // 最大空闲连接数, 默认8个
        jedisPoolConfig.setMaxIdle(config.getMaxIdleCons());
        // 最大连接数, 默认8个
        jedisPoolConfig.setMaxTotal(config.getMaxTolalCons());
        //最小空闲连接数, 默认0
        jedisPoolConfig.setMinIdle(config.getMinIdleCons());
        // 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
        jedisPoolConfig.setMaxWaitMillis(config.getMaxWaitTime()); // 设置2秒
        //对拿到的connection进行validateObject校验
        jedisPoolConfig.setTestOnBorrow(config.isTestOnBorrow());
	}
}
